﻿using CPAIS.Model;
using System;
using System.Xml;
using System.Collections.Generic;

namespace CPAIS.LogParser.PluginsWithXmlDocument
{
    /// <summary>
    /// Log parser for parsing event log file with XML Root TAG 'Eventlog', like:
    /// 
    /// <Eventlog>
    ///     <Case CP_ID="5" Visit_ID="2" OutPatient_ID="10160" InPatient_ID="364780" Diagnosis_Date="2008-06-13T16:57:43.000" Admit_Date="2008-06-13T16:57:43.000" Discharge_Date="2008-06-18T16:00:00.000" BirthDay="1930-01-10T00:00:00.000" Sex="女" Department="心内监护室" Cost="3263.17">
    ///         <Diagnosis>
    ///             <Diagnosis Diagnosis=" 冠状动脉粥样硬化性心脏病" ID="D1" />
    ///             <Diagnosis Diagnosis="心律失常-频发室性早搏" ID="D14" />
    ///         </Diagnosis>
    ///         <Case>
    ///             <Event ID="OS33" Day="0" />
    ///             <Event ID="A5" Day="4" />
    ///         </Case>
    ///     </Case>
    /// </Eventlog>
    /// 
    /// </summary>
    public class LogParserA : ILogParserWithXmlDocument
    {
        #region String used for parsing XML file
        private const string EventLog = "Eventlog";
        private const string Case = "Case";
        private const string Visit_ID = "Visit_ID";
        private const string InPatient_ID = "InPatient_ID";
        private const string Admit_Date = "Admit_Date";
        private const string Discharge_Date = "Discharge_Date";
        private const string BirthDay = "BirthDay";
        private const string Sex = "Sex";
        private const string Department = "Department";
        private const string Cost = "Cost";
        private const string Diagnosis = "Diagnosis";
        private const string Event = "Event";
        private const string ID = "ID";
        private const string Day = "Day";

        private const string Male = "男";
        private const string Female = "女";
        private const char Observ = 'O';
        private const char Action = 'A';

        private const string KnowledgeBase = "KnowledgeBase";
        private const string Context = "Context";
        private const string Id_Index = "Id_Index";
        private const string Type = "Type";
        private const string Col_Name = "Col_Name";
        #endregion

        private class KnowledgeBaseItem
        {
            public string Id_Index;
            public string Type;
            public string ID;
            public string Col_Name;
        }

        private Dictionary<string, KnowledgeBaseItem> knowledgeBase;
        public LogParserA()
        {
            knowledgeBase = new Dictionary<string, KnowledgeBaseItem>();
        }

        public string XmlTag
        {
            get { return EventLog; }
        }

        public void Parse(LogModel logModel, XmlNode rootNode, Updater.StateUpdater updater)
        {
            foreach (XmlNode node in rootNode.ChildNodes)
            {
                if (node.Name == KnowledgeBase)
                {
                    foreach (XmlNode sNode in node.ChildNodes)
                    {
                        KnowledgeBaseItem item = new KnowledgeBaseItem();
                        item.Id_Index = node.Attributes[Id_Index].ToString();
                        item.Type = node.Attributes[Type].ToString();
                        item.ID = node.Attributes[ID].ToString();
                        item.Col_Name = node.Attributes[Col_Name].ToString();
                    }
                }
                else if (node.Name == Case)
                {
                    #region Trace
                    
                    string strPid = node.Attributes[InPatient_ID].Value.Trim();
                    string strAdmitTime = node.Attributes[Admit_Date].Value.Trim();
                    string strDischargeTime = node.Attributes[Discharge_Date].Value.Trim();
                    string strBirthday = node.Attributes[BirthDay].Value.Trim();
                    string strSex = node.Attributes[Sex].Value.Trim();
                    string strDepartment = node.Attributes[Department].Value.Trim();
                    string strCost = node.Attributes[Cost].Value.Trim();

                    Trace trace = new Trace(logModel, strPid);
                    trace.Admit = DateTime.Parse(strAdmitTime);
                    trace.Discharge = DateTime.Parse(strDischargeTime);
                    trace.Birthday = DateTime.Parse(strBirthday);
                    trace.Sex = strSex == Male ? SexType.Male : (strSex == Female ? SexType.Female : SexType.Unknown);
                    trace.Department = strDepartment;
                    double cost;
                    if (double.TryParse(strCost, out cost))
                        trace.Cost = cost;

                    foreach (XmlNode sNode in node)
                    {
                        if (sNode.Name == Diagnosis)
                        {
                            foreach (XmlNode tNode in sNode)
                            {
                                if (tNode.Name == Diagnosis)
                                {
                                    string diagName = tNode.Attributes[Diagnosis].Value.Trim();
                                    trace.AddDiagnosis(diagName);
                                }
                            }
                        }
                        else if (sNode.Name == Case)
                        {
                            foreach (XmlNode tNode in sNode)
                            {
                                if (tNode.Name == Event)
                                {
                                    string typeName = tNode.Attributes[ID].Value.Trim();
                                    string strDay = tNode.Attributes[Day].Value.Trim();
                                    int day = int.Parse(strDay);
                                    if (typeName[0] == Observ)
                                    {
                                        ObservationEvent entry = new ObservationEvent(trace, day, typeName);
                                        trace.AddObservation(entry);
                                    }
                                    else if (typeName[0] == Action)
                                    {
                                        // Map the action name
                                        if (knowledgeBase.ContainsKey(typeName))
                                            typeName = knowledgeBase[typeName].ID;

                                        ActionEvent entry = new ActionEvent(trace, day, typeName);
                                        trace.AddAction(entry);
                                    }
                                }
                            }
                        }
                    }
                    if (knowledgeBase.ContainsKey("A0"))
                        trace.AddAction(new ActionEvent(trace, 0, knowledgeBase["A0"].ID));
                    else
                        trace.AddAction(new ActionEvent(trace, 0, "A0"));
                    trace.OrderTrace();
                    logModel.AddTrace(trace);
                    if (updater != null)
                        updater.UpdateMessage(string.Format("{0} traces have been loaded...", logModel.TraceCount));

                    #endregion
                }
            }
        }
    }
}